<?php

namespace App\Algorithm;

class ScheduleAlgorithm
{

    /**
     * 计算指定日期排班
     * @param int $workStartTime 上班开始时间
     * @param int $workEndTime 上班结束时间
     * @param array $reservedTimeSlots 已经预约或者使用时间
     * @return array
     */
    public function scheduling(int $workStartTime, int $workEndTime, array $reservedTimeSlots, $lessonDuration = 60)
    {





        //判断 上班时间 和第一个预约时间的冲突
        if (isset($reservedTimeSlots[0]['start'])) {


            $diff = $workStartTime + $lessonDuration*60 + 10*60;


            if ($reservedTimeSlots[0]['start'] > $workStartTime) {
                //上班开始时间 和第一个预约时间冲突 时间跳转到休息结束
                if ($diff > $reservedTimeSlots[0]['start']){
                    $workStartTime = $reservedTimeSlots[0]['end'] + 600;
                }
            }else{// 已经到第一个预约时间点了 直接跳到休息结束
                $workStartTime = $reservedTimeSlots[0]['end'] + 600;
            }
        }


        // 预约结束后加上休息时间，并将这些时间段添加到预约时间段数组中
        foreach ($reservedTimeSlots as $key => $reservedSlot) {
            $reservedTimeSlots[$key]['start'] = $reservedSlot['start'] - 600;
            $reservedTimeSlots[$key]['end'] = $reservedSlot['end'] + 600;

        }


        // 可用排班时间段
        $availableTimeSlots = [];

        // 初始化可用排班时间段，开始时间为上班开始时间，结束时间为上班结束时间
        $availableTimeSlots[] = ['start' => $workStartTime, 'end' => $workEndTime];

        // 遍历预约的时间段，将预约的时间段从可用排班时间段中剔除
        foreach ($reservedTimeSlots as $reservedSlot) {
            $reservedStart = $reservedSlot['start'];
            $reservedEnd = $reservedSlot['end'];

            // 遍历可用排班时间段，查找与预约时间段重叠的部分
            foreach ($availableTimeSlots as $key => $availableSlot) {
                $availableStart = $availableSlot['start'];
                $availableEnd = $availableSlot['end'];

                // 如果预约的时间段与可用排班时间段重叠，则将重叠部分从可用排班时间段中剔除
                if ($reservedStart <= $availableEnd && $reservedEnd >= $availableStart) {
                    // 判断是否有左边重叠部分，有则剔除
                    if ($reservedStart > $availableStart) {
                        $availableTimeSlots[$key]['end'] = $reservedStart;
                    }

                    // 判断是否有右边重叠部分，有则剔除
                    if ($reservedEnd < $availableEnd) {
                        $newSlot = ['start' => $reservedEnd, 'end' => $availableEnd];
                        array_splice($availableTimeSlots, $key + 1, 0, [$newSlot]);
                    }
                }
            }
        }

        // 遍历可用排班时间段，将每节课的开始时间调整为整十分，并判断是否超出上班时间和预约时间段的结束时间
        foreach ($availableTimeSlots as &$slot) {
            $slot['start'] = ceil($slot['start'] / 600) * 600;
            $slot['end'] = ceil($slot['end'] / 600) * 600;
            if ($slot['start'] >= $slot['end']) {
                // 如果开始时间超过了结束时间，则删除该时间段
                unset($slot);
            }
        }


        // 每节课时长（60分钟）
        $lessonDuration = 60;

        // 休息时长（10分钟）
        $breakDuration = 10;

        // 存储最终排班结果的数组
        $finalSchedule = [];

        // 循环遍历可用排班时间段
        foreach ($availableTimeSlots as $timeSlot) {
            $start = $timeSlot['start'];
            $end = $timeSlot['end'];

            // 计算该时间段内有多少个60分钟的小时间段
            $numOfSlots = floor(($end - $start) / ($lessonDuration * 60));


            // 循环遍历小时间段，并将其加入最终排班结果数组
            for ($i = 0; $i < $numOfSlots; $i++) {
                // 计算工作时间段的起始时间和结束时间
                $workSlotStart = $start + $i * ($lessonDuration + $breakDuration) * 60;
                $workSlotEnd = $workSlotStart + $lessonDuration * 60;

                // 将工作时间段加入最终排班结果数组
                $finalSchedule[] = [
                    'start' => $workSlotStart,
                    'end' => $workSlotEnd,
                ];

            }
        }

        return $finalSchedule;
    }


    public function isOverlapping($start1, $end1, $start2, $end2)
    {
        return ($start1 < $end2 && $start2 < $end1);
    }

    public function isInTimeRange($start, $end, $rangeStart, $rangeEnd)
    {
        return ($start >= $rangeStart && $end <= $rangeEnd);
    }

    /**
     * 判断时间是否可用
     * @param $rangeStart 范围开始时间
     * @param $rangeEnd 范围结束时间
     * @param $occupiedTimeSlots 被占用的时间段信息
     * @param $desiredStart 想要的开始时间
     * @param $desiredEnd 想要的结束时间
     * @return bool
     */
    public function isTimeSlotAvailable($rangeStart, $rangeEnd, $occupiedTimeSlots, $desiredStart, $desiredEnd)
    {
        // 检查小区间是否在大区间内
        if (!$this->isInTimeRange($desiredStart, $desiredEnd, $rangeStart, $rangeEnd)) {
            return false;
        }

        // 检查小区间是否和任何已被占用的时间段重叠
        foreach ($occupiedTimeSlots as $occupiedSlot) {
            if ($this->isOverlapping($desiredStart, $desiredEnd, $occupiedSlot['start'], $occupiedSlot['end'])) {
                return false;
            }
        }

        return true;
    }


}